//    Openbravo POS is a point of sales application designed for touch screens.
//    Copyright (C) 2007-2009 Openbravo, S.L.
//    http://www.openbravo.com/product/pos
//
//    This file is part of Openbravo POS.
//
//    Openbravo POS is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    Openbravo POS is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with Openbravo POS.  If not, see <http://www.gnu.org/licenses/>.
package cn.ekuma.epos.datalogic.define;

import com.openbravo.data.loader.key.KeyBuilder;
import com.openbravo.data.loader.sentence.SentenceExecTransaction;
import com.openbravo.data.loader.sentence.StaticSentence;
import com.openbravo.data.loader.serialize.serializer.write.SerializerWriteString;
import com.openbravo.data.loader.table.I_TableSentenceBuilder;
import e.odbo.data.dao.DataLogic;
import e.odbo.data.dao.EntityManager;
import e.odbo.data.dao.I_ParentNode;
import e.odbo.data.dao.ParentNodeWarp;
import e.odbo.data.bean.IKeyed;
import cn.ekuma.epos.bean.util.sale.TicketHelper;
import cn.ekuma.epos.bean.util.sale.TicketLineHelper;
import cn.ekuma.epos.datalogic.I_CustomerDebtProcesser;
import cn.ekuma.epos.datalogic.I_DataLogicSales;
import cn.ekuma.epos.datalogic.I_ProductRecommend;
import cn.ekuma.epos.datalogic.define.dao.AttributeDAO;
import cn.ekuma.epos.datalogic.define.dao.AttributeInstInfoDAO;
import cn.ekuma.epos.datalogic.define.dao.AttributeInstanceDAO;
import cn.ekuma.epos.datalogic.define.dao.AttributeSetDAO;
import cn.ekuma.epos.datalogic.define.dao.AttributeSetInstanceDAO;
import cn.ekuma.epos.datalogic.define.dao.AttributeUseDAO;
import cn.ekuma.epos.datalogic.define.dao.AttributeValueDAO;
import cn.ekuma.epos.datalogic.define.dao.BomIncludeProductInfoDAO;
import cn.ekuma.epos.datalogic.define.dao.CustomerStorckCurrentDAO;
import cn.ekuma.epos.datalogic.define.dao.LocationLayoutCurrentDAO;
import cn.ekuma.epos.datalogic.define.dao.LocationLayoutDAO;
import cn.ekuma.epos.datalogic.define.dao.PlaceStateDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductAttributeValuePriceDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductLocationStateDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductLotNoStockCurrentDAO;
import cn.ekuma.epos.datalogic.define.dao.ModuleDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductBomDAO;
import cn.ekuma.epos.datalogic.define.dao.CloseCashDAO;
import cn.ekuma.epos.datalogic.define.dao.CustomerCategoryDAO;
import cn.ekuma.epos.datalogic.define.dao.CustomerCategoryExtDAO;
import cn.ekuma.epos.datalogic.define.dao.CustomerDAO;
import cn.ekuma.epos.datalogic.define.dao.CustomerInfoDAO;
import cn.ekuma.epos.datalogic.define.dao.FloorDAO;
import cn.ekuma.epos.datalogic.define.dao.FloorExtDAO;
import cn.ekuma.epos.datalogic.define.dao.LocationDAO;
import cn.ekuma.epos.datalogic.define.dao.PaymentDAO;
import cn.ekuma.epos.datalogic.define.dao.PaymentInfoTicketDAO;
import cn.ekuma.epos.datalogic.define.dao.PlaceDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductAuxiliarDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductCategoryDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductCategoryExtDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductCodeDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductCustomerCategoryPriceDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductExtDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductPrefPriceDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductPriceDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductScoreDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductStoreDiaryViewDAO;
import cn.ekuma.epos.datalogic.define.dao.ProductStoreInfoDAO;
import cn.ekuma.epos.datalogic.define.dao.Product_VDAO;
import cn.ekuma.epos.datalogic.define.dao.RantDAO;
import cn.ekuma.epos.datalogic.define.dao.ReceiptDAO;
import cn.ekuma.epos.datalogic.define.dao.ReservationDAO;
import cn.ekuma.epos.datalogic.define.dao.ServiceCalendarDAO;
import cn.ekuma.epos.datalogic.define.dao.ServiceCalendarDayLineDAO;
import cn.ekuma.epos.datalogic.define.dao.ServiceCalendarWeakLineDAO;
import cn.ekuma.epos.datalogic.define.dao.ServiceDAO;
import cn.ekuma.epos.datalogic.define.dao.ServiceDayStateDAO;
import cn.ekuma.epos.datalogic.define.dao.StockCurrentDAO;
import cn.ekuma.epos.datalogic.define.dao.StockDiaryDAO;
import cn.ekuma.epos.datalogic.define.dao.TaxCategoryDAO;
import cn.ekuma.epos.datalogic.define.dao.TaxCustCategoryDAO;
import cn.ekuma.epos.datalogic.define.dao.TaxDAO;
import cn.ekuma.epos.datalogic.define.dao.TaxLineDAO;
import cn.ekuma.epos.datalogic.define.dao.UserDAO;
import cn.ekuma.epos.datalogic.define.dao.UserInfoDAO;
import cn.ekuma.epos.datalogic.define.dao.crm.CustomerProductDAO;
import cn.ekuma.epos.datalogic.define.dao.crm.CustomerScoreDiaryDAO;
import cn.ekuma.epos.datalogic.define.dao.crm.CustomerStoreValueCardDAO;
import cn.ekuma.epos.datalogic.define.dao.crm.CustomerStoreValueCardDiaryDAO;
import cn.ekuma.epos.datalogic.define.dao.crm.ProductCustomerViewDAO;
import cn.ekuma.epos.datalogic.define.dao.crm.physicalbond.PhysicalBondDAO;
import cn.ekuma.epos.datalogic.define.dao.crm.voucher.VoucherDAO;
import cn.ekuma.epos.datalogic.define.dao.crm.voucher.VoucherDiaryDAO;
import cn.ekuma.epos.datalogic.define.dao.kuaidi.KuaiDiDAO;
import cn.ekuma.epos.datalogic.define.dao.pda.LocalHistoryDAO;
import cn.ekuma.epos.datalogic.define.dao.sale.FindTicketsInfoDAO;
import cn.ekuma.epos.datalogic.define.dao.sale.PosSharedProductDAO;
import cn.ekuma.epos.datalogic.define.dao.sale.QuickPaymentDAO;
import cn.ekuma.epos.datalogic.define.dao.sale.QuickProductDAO;
import cn.ekuma.epos.datalogic.define.dao.sale.TicketDAO;
import cn.ekuma.epos.datalogic.define.dao.sale.TicketLineDAO;
import cn.ekuma.epos.datalogic.define.dao.sale.kitchen.KitchenLineDAO;
import cn.ekuma.epos.datalogic.define.dao.sale.kitchen.KitchenLineInfoDAO;
import cn.ekuma.epos.datalogic.define.dao.sale.kitchen.KitchenWorkLineDAO;
import cn.ekuma.epos.db.table.crm.physicalbond.I_PhysicalBond;

import com.openbravo.bean.ServiceCalendarDayLine;
import com.openbravo.bean.ServiceCalendarWeakLine;
import com.openbravo.pos.bean.ProductCategoryExt;
import com.openbravo.pos.bean.ProductExt;
import com.openbravo.pos.bean.QuickPayment;
import com.openbravo.pos.util.RoundUtils;
import com.openbravo.pos.util.StringUtils;
import com.openbravo.bean.Service;
import com.openbravo.bean.sales.QuickProduct;
import com.openbravo.bean.sales.Ticket;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import com.openbravo.data.loader.*;
import com.openbravo.data.basic.BasicException;
import com.openbravo.bean.sales.TicketLine;
import com.openbravo.bean.BusinessPartner;
import com.openbravo.bean.Payment;
import com.openbravo.bean.shard.MovementReason;
import com.openbravo.bean.AttributeInstInfo;
import com.openbravo.bean.AttributeValue;
import com.openbravo.bean.BomIncludeProductInfo;
import com.openbravo.bean.PaymentInfo;
import com.openbravo.bean.PaymentsModel;
import com.openbravo.bean.Place;
import com.openbravo.bean.Product;
import com.openbravo.bean.ProductAttributeValuePrice;
import com.openbravo.bean.ProductBom;
import com.openbravo.bean.ProductCustomerCategoryPrice;
import com.openbravo.bean.ProductPrefPrice;
import com.openbravo.bean.ProductPrice;
import com.openbravo.bean.ProductScore;
import com.openbravo.bean.StockDiary;
import com.openbravo.bean.viewbean.ProductStoreView;
import com.openbravo.bean.viewbean.Product_V;
import com.openbravo.bean.Receipt;
import com.openbravo.bean.TaxLine;
import com.openbravo.bean.shard.IncludeTaxs;
import com.openbravo.bean.crm.CustomerProduct;
import com.openbravo.bean.crm.CustomerScoreDiary;
import com.openbravo.bean.crm.CustomerScoreOPEnum;
import com.openbravo.bean.crm.CustomerStoreValueCard;
import com.openbravo.bean.crm.CustomerStoreValueCardDiary;
import com.openbravo.bean.crm.StoreValueCardOPEnum;
import com.openbravo.bean.crm.physicalbond.PhysicalBond;
import com.openbravo.bean.crm.viewbean.ProductCustomerView;
import com.openbravo.bean.crm.voucher.Voucher;
import com.openbravo.bean.crm.voucher.VoucherDiary;
import com.openbravo.bean.crm.voucher.VoucherOPEnum;
import com.openbravo.bean.infobean.UserInfo;

/**
 *
 * @author adrianromero
 */
public class DataLogicSales extends DataLogic implements I_DataLogicSales {

    protected ProductExtDAO productExtDAO;
    protected ProductDAO productDAO;
    protected ProductAuxiliarDAO productAuxiliarDAO;
    protected ProductCategoryExtDAO productCategoryExtDAO;
    protected ProductCategoryDAO productCategoryDAO;
    protected UserInfoDAO userInfoDAO;
    protected UserDAO userDAO;
    protected TaxDAO taxDAO;
    protected CustomerDAO customerDAO;
    protected CustomerInfoDAO customerInfoDAO;
    protected ProductBomDAO bomProductDAO;
    protected CustomerCategoryExtDAO customerCategoryExtDAO;
    protected CustomerCategoryDAO customerCategoryDAO;
    protected LocationDAO locationDAO;
    protected PlaceDAO placeDAO;
    protected TaxCustCategoryDAO taxCustCategoryDAO;
    protected TaxCategoryDAO taxCategoryDAO;
    protected CloseCashDAO closeCashDAO;
    protected StockCurrentDAO stockCurrentDAO;
    protected StockDiaryDAO stockDiaryDAO;
    protected ProductPrefPriceDAO productPrefPriceDAO;
    protected RantDAO rantDAO;
    protected ProductCustomerCategoryPriceDAO productCustomerCategoryPriceDAO;
    protected ServiceDAO serviceDAO;
    protected ProductStoreInfoDAO productStoreInfoDAO;
    protected FindTicketsInfoDAO findTicketsInfoDAO;
    protected ReceiptDAO receiptDAO;
    protected PaymentDAO paymentDAO;
    protected TaxLineDAO taxLineDAO;
    protected TicketDAO ticketDAO;
    protected TicketLineDAO ticketLineDAO;
    protected PaymentInfoTicketDAO paymentInfoTicketDAO;
    protected ServiceDayStateDAO serviceDayStateDAO;
    protected ServiceCalendarWeakLineDAO serviceCalendarWeakLineDAO;
    protected ServiceCalendarDayLineDAO serviceCalendarDayLineDAO;
    protected ServiceCalendarDAO serviceCalendarDAO;
    protected AttributeDAO attributeDAO;
    protected AttributeValueDAO attributeValueDAO;
    protected AttributeSetDAO attributeSetDAO;
    protected AttributeUseDAO attributeUseDAO;
    protected ProductCodeDAO productCodeDAO;
    protected KitchenWorkLineDAO kitchenWorkLineDAO;
    protected KitchenLineInfoDAO kitchenLineInfoDAO;
    protected KitchenLineDAO kitchenLineDAO;
    
    protected FloorExtDAO floorExtDAO;
    protected FloorDAO floorDAO;
    protected QuickPaymentDAO puickPaymentDAO;
    protected ReservationDAO reservationDAO;
    protected Collection<I_CustomerDebtProcesser> customerDebtProcessers;
    protected ModuleDAO moduleDAO;
    
    protected ProductLotNoStockCurrentDAO lotNoStockCurrentDAO;
    
    protected Product_VDAO product_VDAO;
    
    protected CustomerStorckCurrentDAO  customerStorckCurrentDAO;
    
    protected Collection<I_ProductRecommend> productRecommends;
    
    protected CustomerStoreValueCardDAO customerStoreValueCardDAO;
    
    protected CustomerStoreValueCardDiaryDAO customerStoreValueCardDiaryDAO;
    
    protected CustomerScoreDiaryDAO customerScoreDiaryDAO;
    
    protected CustomerProductDAO customerProductDAO;
    
    protected ProductCustomerViewDAO productCustomerViewDAO;
    
    protected ProductPriceDAO productPriceDAO;
    
    protected VoucherDAO voucherDAO;
    
    protected VoucherDiaryDAO voucherDiaryDAO;
    
    protected ProductScoreDAO productScoreDAO;
	protected QuickProductDAO quickProductDAO;
	protected LocationLayoutDAO locationLayoutDAO;
	protected LocationLayoutCurrentDAO locationLayoutCurrentDAO;
	
	protected ProductLocationStateDAO productLocationStateDAO;
	
	protected AttributeInstInfoDAO attributeInstInfoDAO;
	
	protected AttributeSetInstanceDAO attributeSetInstanceDAO;
	
	protected AttributeInstanceDAO attributeInstanceDAO;
	
	protected PosSharedProductDAO posSharedProductDAO;
	
	
	protected ProductAttributeValuePriceDAO productAttributeValuePriceDAO;
	
	protected BomIncludeProductInfoDAO bomIncludeProductInfoDAO;
	
	protected ProductStoreDiaryViewDAO productStoreDiaryViewDAO;
	private LocalHistoryDAO localHistoryDAO;
	protected PhysicalBondDAO physicalBondDAO;
	private PlaceStateDAO placeStateDAO;
	
	private KuaiDiDAO kuaiDiDAO;

    public DataLogicSales(EntityManager entityManager, Collection<I_CustomerDebtProcesser> customerDebtProcessers, Collection<I_ProductRecommend> productRecommends) {
        super(entityManager);
        this.customerDebtProcessers=customerDebtProcessers;
        if(customerDebtProcessers==null){
            customerDebtProcessers=new ArrayList();
        }

        this.productRecommends=productRecommends;
        if(productRecommends==null){
            productRecommends=new ArrayList();
        }

        moduleDAO=new ModuleDAO(s);
        addDaoToMap(moduleDAO);

        productExtDAO = new ProductExtDAO(s);
        addDaoToMap(productExtDAO);

        productCategoryExtDAO = new ProductCategoryExtDAO(s);
        addDaoToMap(productCategoryExtDAO);

        userDAO = new UserDAO(s);
        addDaoToMap(userDAO);

        userInfoDAO = new UserInfoDAO(userDAO);
        addDaoToMap(userInfoDAO);

        taxDAO = new TaxDAO(s);
        addDaoToMap(taxDAO);

        customerDAO = new CustomerDAO(s);
        addDaoToMap(customerDAO);

        customerInfoDAO=new CustomerInfoDAO(customerDAO);
        addDaoToMap(customerInfoDAO);

        productDAO = new ProductDAO(s);
        addDaoToMap(productDAO);

        bomProductDAO = new ProductBomDAO(s, productDAO);
        addDaoToMap(bomProductDAO);

        customerCategoryExtDAO = new CustomerCategoryExtDAO(s);
        addDaoToMap(customerCategoryExtDAO);

        customerCategoryDAO = new CustomerCategoryDAO(s);
        addDaoToMap(customerCategoryDAO);

        locationDAO = new LocationDAO(s);
        addDaoToMap(locationDAO);

        placeDAO = new PlaceDAO(s);
        addDaoToMap(placeDAO);

        taxCustCategoryDAO = new TaxCustCategoryDAO(s);
        addDaoToMap(taxCustCategoryDAO);

        taxCategoryDAO = new TaxCategoryDAO(s);
        addDaoToMap(taxCategoryDAO);

        closeCashDAO = new CloseCashDAO(s);
        addDaoToMap(closeCashDAO);

        stockCurrentDAO = new StockCurrentDAO(s);
        addDaoToMap(stockCurrentDAO);

        stockDiaryDAO=new StockDiaryDAO(s);
        addDaoToMap(stockDiaryDAO);

        productPrefPriceDAO = new ProductPrefPriceDAO(s);
        addDaoToMap(productPrefPriceDAO);

        rantDAO = new RantDAO(s);
        addDaoToMap(rantDAO);

        productCustomerCategoryPriceDAO = new ProductCustomerCategoryPriceDAO(s, customerCategoryDAO);
        addDaoToMap(productCustomerCategoryPriceDAO);

        serviceDAO = new ServiceDAO(s);
        addDaoToMap(serviceDAO);

        productStoreInfoDAO = new ProductStoreInfoDAO(s);
        addDaoToMap(productStoreInfoDAO);

        findTicketsInfoDAO = new FindTicketsInfoDAO(s);
        addDaoToMap(findTicketsInfoDAO);

        attributeDAO=new AttributeDAO(s);
        addDaoToMap(attributeDAO);
        attributeValueDAO=new AttributeValueDAO(s);
        addDaoToMap(attributeValueDAO);
        attributeSetDAO=new AttributeSetDAO(s);
        addDaoToMap(attributeSetDAO);
        attributeUseDAO=new AttributeUseDAO(s);
        addDaoToMap(attributeUseDAO);

        receiptDAO = new ReceiptDAO(s);
        addDaoToMap(receiptDAO);

        paymentDAO = new PaymentDAO(s);
        addDaoToMap(paymentDAO);

        taxLineDAO = new TaxLineDAO(s);
        addDaoToMap(taxLineDAO);

        productAuxiliarDAO=new ProductAuxiliarDAO(s,productDAO);
        addDaoToMap(productAuxiliarDAO);

        ticketDAO = new TicketDAO(s);
        addDaoToMap(ticketDAO);

        ticketLineDAO = new TicketLineDAO(s);
        addDaoToMap(ticketLineDAO);

        paymentInfoTicketDAO = new PaymentInfoTicketDAO(s);
        addDaoToMap(paymentInfoTicketDAO);

        productCategoryDAO = new ProductCategoryDAO(s);
        addDaoToMap(productCategoryDAO);

        serviceDayStateDAO = new ServiceDayStateDAO(s);
        addDaoToMap(serviceDayStateDAO);

        serviceCalendarWeakLineDAO = new ServiceCalendarWeakLineDAO(s);
        addDaoToMap(serviceCalendarWeakLineDAO);

        serviceCalendarDayLineDAO = new ServiceCalendarDayLineDAO(s);
        addDaoToMap(serviceCalendarDayLineDAO);

        serviceCalendarDAO = new ServiceCalendarDAO(s);
        addDaoToMap(serviceCalendarDAO);

        productCodeDAO=new ProductCodeDAO(s);
        addDaoToMap(productCodeDAO);

        kitchenWorkLineDAO=new KitchenWorkLineDAO(s);
        addDaoToMap(kitchenWorkLineDAO);

        kitchenLineInfoDAO=new KitchenLineInfoDAO(s);
        addDaoToMap(kitchenLineInfoDAO);

        kitchenLineDAO=new KitchenLineDAO(s);
        addDaoToMap(kitchenLineDAO);

        floorExtDAO=new FloorExtDAO(s);
        addDaoToMap(floorExtDAO);

        floorDAO=new FloorDAO(s);
        addDaoToMap(floorDAO);

        puickPaymentDAO=new QuickPaymentDAO(s,receiptDAO,paymentInfoTicketDAO);

        reservationDAO=new ReservationDAO(s,customerInfoDAO);
        addDaoToMap(reservationDAO);

        lotNoStockCurrentDAO=new ProductLotNoStockCurrentDAO(s);
        addDaoToMap(lotNoStockCurrentDAO);

        product_VDAO=new Product_VDAO(s);
        addDaoToMap(product_VDAO);

        customerStorckCurrentDAO=new CustomerStorckCurrentDAO(s);
        addDaoToMap(customerStorckCurrentDAO);

        customerStoreValueCardDAO=new CustomerStoreValueCardDAO(s);
        addDaoToMap(customerStoreValueCardDAO);

        customerStoreValueCardDiaryDAO=new CustomerStoreValueCardDiaryDAO(s);
        addDaoToMap(customerStoreValueCardDiaryDAO);

        customerScoreDiaryDAO=new CustomerScoreDiaryDAO(s);
        addDaoToMap(customerScoreDiaryDAO);

        customerProductDAO=new CustomerProductDAO(s);
        addDaoToMap(customerProductDAO);

        productCustomerViewDAO=new ProductCustomerViewDAO(s, customerProductDAO);
        addDaoToMap(productCustomerViewDAO);


        productPriceDAO=new ProductPriceDAO(s);
        addDaoToMap(productPriceDAO);

        voucherDAO=new VoucherDAO(s);
        addDaoToMap(voucherDAO);

        voucherDiaryDAO=new VoucherDiaryDAO(s);
        addDaoToMap(voucherDiaryDAO);

        productScoreDAO=new ProductScoreDAO(s);
        addDaoToMap(productScoreDAO);

        quickProductDAO=new QuickProductDAO(s);
        addDaoToMap(quickProductDAO);

        locationLayoutDAO=new LocationLayoutDAO(s);
        addDaoToMap(locationLayoutDAO);

        locationLayoutCurrentDAO=new LocationLayoutCurrentDAO(s);
        addDaoToMap(locationLayoutCurrentDAO);

        productLocationStateDAO=new ProductLocationStateDAO(s);
        addDaoToMap(productLocationStateDAO);


        attributeInstInfoDAO=new AttributeInstInfoDAO(s);
        addDaoToMap(attributeInstInfoDAO);

        attributeSetInstanceDAO=new AttributeSetInstanceDAO(s);
        addDaoToMap(attributeSetInstanceDAO);

        productAttributeValuePriceDAO=new ProductAttributeValuePriceDAO(s);
        addDaoToMap(productAttributeValuePriceDAO);

        attributeInstanceDAO=new AttributeInstanceDAO(s);
        addDaoToMap(attributeInstanceDAO);

        posSharedProductDAO=new PosSharedProductDAO(s);
        addDaoToMap(posSharedProductDAO);

        localHistoryDAO=new LocalHistoryDAO(s);
        addDaoToMap(localHistoryDAO);

        bomIncludeProductInfoDAO=new BomIncludeProductInfoDAO(s);
        addDaoToMap(bomIncludeProductInfoDAO);

        productStoreDiaryViewDAO=new ProductStoreDiaryViewDAO(s);
        addDaoToMap(productStoreDiaryViewDAO);

        physicalBondDAO=new PhysicalBondDAO(s);
        addDaoToMap(physicalBondDAO);

        placeStateDAO=new PlaceStateDAO(s);
        addDaoToMap(placeStateDAO);

        kuaiDiDAO=new KuaiDiDAO(s);
        addDaoToMap(kuaiDiDAO);

    }

    public final List<Product> getBomIncludeProductList(String code) throws BasicException {
        return productDAO.getBomIncludeProductList(code);
    }

    public final List<Product> getBomProductForIncludeList(String code) throws BasicException {
        return productDAO.getBomProductForIncludeList(code);
    }

    public List<Product> getProductBySimilarCode(String code) throws BasicException {
        return productDAO.getProductBySimilarCode(code);
    }

    public List<Product> getProductOnSimilarByCode(String code) throws BasicException {
        return productDAO.getProductOnSimilarByCode(code);
    }

    // Utilidades de productos
    public final Product getProductInfo(String id) throws BasicException {
        return productDAO.getProductInfo(id);

    }

    public final List<Product> getProductInfoByCode(String sCode) throws BasicException {
        return productDAO.getProductInfoByCode(sCode);
    }

    public final Product getProductInfoByReference(String sReference) throws BasicException {
        return productDAO.getProductInfoByReference(sReference);
    }

    // Products list
    public List<Product> getProductList(Object filter) throws BasicException {
        return productDAO.getProductList(filter);
    }

    // Products list
    public List<Product> getProductListNormal(Object filter) throws BasicException {
        return productDAO.getProductListNormal(filter);
    }

    //Auxiliar list for a filter
    public List<Product> getProductListAuxiliar(Object filter) throws BasicException {
        return productDAO.getProductListAuxiliar(filter);
    }

    public List<Product> listProductByShared() throws BasicException {
        return productDAO.listProductByShared();
    }
    
    public  List<Product> getBomProductForIncludeListById(String productId)
	throws BasicException{
    	 return productDAO.getBomProductForIncludeListById(productId);
    }

    // Catalogo de productos
    public final List<ProductCategoryExt> getRootProductCategories() throws BasicException {
        return productCategoryExtDAO.getRootProductCategories();
    }

    public final List<ProductCategoryExt> getSubProductCategories(String category) throws BasicException {
        return productCategoryExtDAO.getSubProductCategories(category);
    }

    public List<ProductExt> getProductCatalog(String category) throws BasicException {
        return productExtDAO.getProductCatalog(category);
    }

    public List<ProductExt> getProductComments(String id) throws BasicException {
        return productExtDAO.getProductComments(id);
    }

    public BusinessPartner findCustomerByCard(String card) throws BasicException {
        return customerDAO.findCustomerByCard(card);
    }

    public final boolean isCashActive(String id) throws BasicException {
        return closeCashDAO.isCashActive(id);
    }

    public final Ticket loadTicket(final int tickettype, final int ticketid) throws BasicException {
        Ticket ticket = ticketDAO.loadTicket(tickettype, ticketid);
        if (ticket != null) {
            String customerid = ticket.getCustomerId();
            ticket.setCustomer(customerid == null
                    ? null
                    : customerDAO.find(KeyBuilder.getKey(customerid)));

            ticket.setLines(ticketLineDAO.list(new ParentNodeWarp(ticket)));
            for(TicketLine l:ticket.getLines()){
            	l.setTax(taxDAO.find(l.getTax()));
            }
            ticket.setPayments(paymentInfoTicketDAO.listByReceipt(ticket.getId()));
            ticket.setUser(userInfoDAO.find(KeyBuilder.getKey(ticket.getUser().getId())));
            ticket.setActiveCash(receiptDAO.getTicketCash(ticket.getId()));
        }
        return ticket;
    }

    public final void saveTicket(final Ticket ticket, final String location) throws BasicException {
        ticket.setLocation(location);
        Transaction t = new Transaction(s) {
            public Object transact() throws BasicException {
                // Set Receipt Id
                if (ticket.getTicketId() == 0) {
                    switch (ticket.getTicketType()) {
                        case Ticket.RECEIPT_NORMAL:
                            ticket.setTicketId(getNextTicketIndex().intValue());
                            break;
                        case Ticket.RECEIPT_REFUND:
                            ticket.setTicketId(getNextTicketRefundIndex().intValue());
                            break;
                        case Ticket.RECEIPT_PAYMENT:
                            ticket.setTicketId(getNextTicketPaymentIndex().intValue());
                            break;
                        default:
                            throw new BasicException();
                    }
                }

                if (ticket.getId() == null) {
                    ticket.setM_sId(UUID.randomUUID().toString());
                }
                // new receipt
                receiptDAO.insert(new Receipt(ticket.getId(), ticket.getActiveCash(), ticket.getDate(), ticket.getProperties()));
                ticketDAO.insert(ticket);

                StockDiary diary;
                for (TicketLine l : ticket.getLines()) {
                	l.setM_sTicket(ticket.getId());
                    ticketLineDAO.insert(l);
                    
                    if (l.getProductID() != null) {
                        // update the stock
                    	diary=new StockDiary();
                    	diary.setDate(ticket.getDate());
                    	diary.setLocation(location);
                    	diary.setProductID(l.getProductID());
                    	diary.setProductAttSetInstId(l.getProductAttSetInstId());
                    	diary.setMultiply(l.getMultiply());
                    	diary.setPrice(new Double(TicketLineHelper.getRealPrice(l)));
                    	diary.setLotNo(l.getLotNo());
                    	diary.setValidityDate(l.getValidityDate());
                    	diary.setBomStroe(l.isBomStore());
                    	if(ticket.getTicketType()==Ticket.RECEIPT_NORMAL){
                    		diary.setReason(MovementReason.OUT_POS);
                    		stockDiarySub(diary);
                    		if(l.isIsPrefSell())
                        		productPrefPriceDAO.updateSellNum(l.getPrefSellID(), diary);
                    	}else if(ticket.getTicketType()==Ticket.RECEIPT_REFUND){
                    		diary.setReason(MovementReason.IN_POS);
                    		// Hay que actualizar el stock si el hay producto
                        	stockDiaryAdd(diary);
                    	}
                    }
                }

                double payTotal=0;
                for (final PaymentInfo p : ticket.getPayments()) {
                	payTotal=RoundUtils.add(payTotal, p.getTotal());
                    Payment pay = new Payment();
                    pay.setReceiptID(ticket.getId());
                    pay.setM_sName(p.getName());
                    pay.setM_dTotal(p.getTotal());
                    pay.setM_transactionID(TicketHelper.getTransactionID(ticket));
                    pay.setReturnMessage(TicketHelper.getReturnMessage(ticket));
                    paymentDAO.insert(pay);
                    if ("debt".equals(p.getName()) || "debtpaid".equals(p.getName())) {
                    	updateCurDebt(p.getTotal(), ticket.getDate(), ticket.getCustomer().getId()); 
                    }else if("storeCard".equals(p.getName())){
                    	CustomerStoreValueCardDiary cardDiary=new CustomerStoreValueCardDiary();
                    	cardDiary.setDate(ticket.getDate());
                    	cardDiary.setCardId(p.getTransactionID());
                    	cardDiary.setUserId(ticket.getM_User().getId());
                    	if(ticket.getTicketType()==Ticket.RECEIPT_REFUND){
                    		cardDiary.setPrice(-p.getTotal());
                    		cardDiary.setReason("Pos refund");
                        	customerStoreValueCardDiaryInsert(StoreValueCardOPEnum.recharge,cardDiary);
                    	}else if(ticket.getTicketType()==Ticket.RECEIPT_NORMAL){
                    		cardDiary.setPrice(p.getTotal());
                    	    cardDiary.setReason("Pos Consumer");
                    	    customerStoreValueCardDiaryInsert(StoreValueCardOPEnum.consumer,cardDiary);
                    	}
                    }else if("voucher".equals(p.getName())){
                    	VoucherDiary voucherDiary=new VoucherDiary();
                    	voucherDiary.setDate(ticket.getDate());
                    	voucherDiary.setVoucherId(p.getTransactionID());
                    	voucherDiary.setUserId(ticket.getM_User().getId());
                    	if(ticket.getTicketType()==Ticket.RECEIPT_REFUND){
                    		throw new BasicException("the voucher no refund in front");
                    	}else if(ticket.getTicketType()==Ticket.RECEIPT_NORMAL){
                    		voucherDiary.setReason("Pos Consumer");
                    		voucherDiaryInsert(VoucherOPEnum.consumer,voucherDiary); 
                    	}
                    }
               }
               if(ticket.getCustomer()!=null&&ticket.getTicketType()!=Ticket.RECEIPT_PAYMENT){
            	  double totalScore=ticket.getTotalScore();
            	  CustomerScoreDiary scoreDiary=new CustomerScoreDiary();
            	  scoreDiary.setCustomerId(ticket.getCustomer().getId());
            	  scoreDiary.setDate(ticket.getDate());  
            	  scoreDiary.setUserId(ticket.getM_User().getId());
            	  scoreDiary.setPrice(totalScore);
            	  if(ticket.getTicketType()==Ticket.RECEIPT_NORMAL){
                	  scoreDiary.setReason("pos sale");  
            	  }else if(ticket.getTicketType()==Ticket.RECEIPT_REFUND){
                	  scoreDiary.setReason("pos refund");
            	  }
            	  customerScoreDiaryInsert(CustomerScoreOPEnum.recharge,scoreDiary);
                }
              if (ticket.getTaxes() != null) {
                    for (final IncludeTaxs tickettax : ticket.getTaxes()) {
                        TaxLine obj = new TaxLine();
                        obj.setReceiptID(ticket.getId());
                        obj.setTaxID(tickettax.getTaxInfo().getId());
                        obj.setBase(tickettax.getSubTotal());
                        obj.setAmount(tickettax.getTax());
                        taxLineDAO.insert(obj);
                    }
                }
                return null;
            }
        };
        t.execute();
    }
    
    public final void saveTicketToQuickProduct(final Ticket ticket, final int type) throws BasicException {
    	
    	for (TicketLine l : ticket.getLines()) {
            if (l.getProductID() != null) {
            	QuickProduct qkProduct=new QuickProduct();
            	qkProduct.setCurDate(ticket.getDate());
            	qkProduct.setProductId(l.getProductID());
            	qkProduct.setProductAttr(l.getProductAttSetId());
            	qkProduct.setUnit(l.getMultiply());
            	qkProduct.setRegUserId(ticket.getM_User().getId());
            	qkProduct.setType(type);
            	quickProductDAO.insert(qkProduct);
            }
    	}
    }
    

    public int voucherDiaryInsert(final VoucherOPEnum opType,
    		final VoucherDiary diary) throws BasicException{
    	if(customerDebtProcessers.isEmpty()){
        	return new SentenceExecTransaction(s) {
    			@Override
    			protected int execInTransaction(Object params) throws BasicException{
    				switch(opType){
    				   case lost:
    					   voucherDAO.changeVoucherState(diary.getVoucherId(), Voucher.STATE_Loss);
    					   break;
    				   case recovery:
    					   voucherDAO.changeVoucherState(diary.getVoucherId(), Voucher.STATE_UseAble);
    					   break;
    				   case able:
    					   voucherDAO.changeVoucherState(diary.getVoucherId(), Voucher.STATE_UseAble);
    					   break;
    				   case back:
    					   voucherDAO.changeVoucherState(diary.getVoucherId(), Voucher.STATE_Back);
    					   break;
    				   case invalid:
    					   voucherDAO.changeVoucherState(diary.getVoucherId(), Voucher.STATE_Invalid);
    					   break;
    				   case consumer:
    					   voucherDAO.changeVoucherState(diary.getVoucherId(), Voucher.STATE_Used);
    					   break;
    				}
    				return voucherDiaryDAO.insert(diary);
    			}
        	}.exec();
        	}else for(I_CustomerDebtProcesser processer:customerDebtProcessers){
          	     processer.voucherDiaryInsert(opType, diary);
          	 }
            return 1;
	}


	public final void deleteTicket(final Ticket ticket, final String location) throws BasicException {

        Transaction t = new Transaction(s) {

            public Object transact() throws BasicException {

                // update the inventory
            	StockDiary diary;
                Date d = new Date();
                for (TicketLine l:ticket.getLines()) {
                    if (l.getProductID() != null) {
                    	diary=new StockDiary();
                    	diary.setDate(d);
                    	diary.setReason(l.getMultiply() >= 0.0
                                    ? MovementReason.IN_POS
                                    : MovementReason.OUT_POS);
                    	diary.setLocation(location);
                    	diary.setProductID(l.getProductID());
                    	diary.setProductAttSetInstId(l.getProductAttSetInstId());
                    	diary.setMultiply(l.getMultiply());
                    	diary.setPrice(new Double(TicketLineHelper.getRealPrice(l)));
                    	diary.setLotNo(l.getLotNo());
                    	diary.setValidityDate(l.getValidityDate());
                    	diary.setBomStroe(l.isBomStore());
                        // Hay que actualizar el stock si el hay producto
                    	stockDiaryAdd(diary);
                    }
                }

                double payTotal=0;
                // update customer debts
                for (PaymentInfo p : ticket.getPayments()) {
                	payTotal+=p.getTotal();
                    if ("debt".equals(p.getName()) || "debtpaid".equals(p.getName())) {
                    	updateCurDebt(-p.getTotal(), ticket.getDate(), ticket.getCustomer().getId()); 
                    }else if("storeCard".equals(p.getName())){
                    	CustomerStoreValueCardDiary cardDiary=new CustomerStoreValueCardDiary();
                    	cardDiary.setReason("Pos delete");
                    	cardDiary.setDate(ticket.getDate());       	
                    	cardDiary.setCardId(p.getTransactionID());
                    	cardDiary.setPrice(-p.getTotal());
                    	cardDiary.setUserId(ticket.getM_User().getId());
                    	customerStoreValueCardDiaryInsert(StoreValueCardOPEnum.consumer,cardDiary); 
                    }
                }
                
                if(ticket.getCustomer()!=null){
                  double totalScore=ticket.getTotalScore();
              	  CustomerScoreDiary scoreDiary=new CustomerScoreDiary();
              	  scoreDiary.setCustomerId(ticket.getCustomer().getId());
              	  scoreDiary.setDate(ticket.getDate());
              	  scoreDiary.setPrice(-totalScore);
              	  scoreDiary.setReason("pos sale delete");
              	  scoreDiary.setUserId(ticket.getM_User().getId());
              	  if(ticket.getTicketType()==Ticket.RECEIPT_REFUND){
                  	  scoreDiary.setReason("pos refund delete");
              	  }
        		  customerScoreDiaryInsert(CustomerScoreOPEnum.recharge,scoreDiary);
                  }
               

                // and delete the receipt
                new StaticSentence(s, "DELETE FROM TAXLINES WHERE RECEIPT = ?", SerializerWriteString.INSTANCE).exec(ticket.getId());
                new StaticSentence(s, "DELETE FROM PAYMENTS WHERE RECEIPT = ?", SerializerWriteString.INSTANCE).exec(ticket.getId());
                new StaticSentence(s, "DELETE FROM TICKETLINES WHERE TICKET = ?", SerializerWriteString.INSTANCE).exec(ticket.getId());
                new StaticSentence(s, "DELETE FROM TICKETS WHERE ID = ?", SerializerWriteString.INSTANCE).exec(ticket.getId());
                new StaticSentence(s, "DELETE FROM RECEIPTS WHERE ID = ?", SerializerWriteString.INSTANCE).exec(ticket.getId());
                return null;
            }
        };
        t.execute();
    }

    public final Integer getNextTicketIndex() throws BasicException {
        return (Integer) s.getDialect().getSequenceSentence(s, "TICKETSNUM").find();
    }

    public final Integer getNextTicketRefundIndex() throws BasicException {
        return (Integer) s.getDialect().getSequenceSentence(s, "TICKETSNUM_REFUND").find();
    }

    public final Integer getNextTicketPaymentIndex() throws BasicException {
        return (Integer) s.getDialect().getSequenceSentence(s, "TICKETSNUM_PAYMENT").find();
    }
    
    public void updateCurDebt(final double debt ,final Date date,final String customerId) throws BasicException{
    	if(customerDebtProcessers.isEmpty()){
            // udate customer fields...
            //CustomerHelper.updateCurDebt(ticket.getCustomer(), -p.getTotal(), ticket.getDate());
            // insert customer fields...
    		customerDAO.updateCurDebt(debt, date, customerId);
        	}else{
        		for(I_CustomerDebtProcesser processer:customerDebtProcessers){
            	     processer.updateCurDebt(debt, date, customerId, null);
            	 }
        	} 	
    }
    
    public void updateCurScore(final double score ,final Date date,final String customerId) throws BasicException{
    	if(customerDebtProcessers.isEmpty()){
            // udate customer fields...
            //CustomerHelper.updateCurDebt(ticket.getCustomer(), -p.getTotal(), ticket.getDate());
            // insert customer fields...
    		customerDAO.updateCurScore(customerId,score);
        	}else{
        		for(I_CustomerDebtProcesser processer:customerDebtProcessers){
            	     processer.updateCurScore(score, date, customerId, null);
            	 }
        	} 	
    }

    public int stockDiaryAdd(final StockDiary diary)throws BasicException {
    	return stockDiaryAdd(null,diary);
    }
    
    public int stockDiarySub(final StockDiary diary)throws BasicException {
    	return stockDiarySub(null,diary);
    }
    
    public int stockDiaryAdd(final String customer,final StockDiary diary)throws BasicException {
    	 return new SentenceExecTransaction(s) {
			@Override
			protected int execInTransaction(Object params) throws BasicException{
				StockDiary newDiary;
				if(!diary.isBomStroe()){
					List<BomIncludeProductInfo> bomProduct=listCascadeBomIncludeProductInfoById(diary.getProductID());
					for(BomIncludeProductInfo p:bomProduct){
						newDiary=new StockDiary();
						newDiary.setDate(diary.getDate());
						newDiary.setReason(diary.getReason());
						newDiary.setLocation(diary.getLocation());
						newDiary.setProductID(p.getIncludeProduct());
						//newDiary.setProductAttSetInstId(l.getProductAttSetInstId());
						newDiary.setMultiply(diary.getMultiply()*p.getUnits());
						newDiary.setPrice(diary.getPrice());
						newDiary.setLotNo(diary.getLotNo());
						newDiary.setValidityDate(diary.getValidityDate());
						newDiary.setBomStroe(p.isBomStore());
						newDiary.setBomId(diary.getProductID());
						if(newDiary.isBomStroe()){
							if(customer!=null)
							    customerStorckCurrentDAO.stockAdd(customer, diary);	
							stockCurrentDAO.stockAdd(newDiary);
							/**if(diary.getLotNo()!=null){
								 if(Math.abs(newDiary.getMultiply())==1.0){
								    ArrayList<String> lotNos=com.openbravo.pos.util.StringUtils.splitProp(diary.getLotNo());
								    for(String s:lotNos){
								    	newDiary.setLotNo(s);
								    	lotNoStockCurrentDAO.stockAdd(newDiary);
								    }	    
								 }else
									 lotNoStockCurrentDAO.stockAdd(newDiary);
							 }	**/					
						 }
					    stockDiaryDAO.insert(newDiary);
						
					}
				}else{
					if(customer!=null)
						customerStorckCurrentDAO.stockAdd(customer, diary);
					  stockCurrentDAO.stockAdd(diary);
			       if(diary.getLotNo()!=null){
						    ArrayList<String> lotNos=com.openbravo.pos.util.StringUtils.splitProp(diary.getLotNo(),"\n");
						    for(String s:lotNos){
						    	newDiary=new StockDiary();
								newDiary.setDate(diary.getDate());
								newDiary.setReason(diary.getReason());
								newDiary.setLocation(diary.getLocation());
								newDiary.setProductID(diary.getProductID());
								if(lotNos.size()==1){
									newDiary.setMultiply(diary.getMultiply());
								}else
								    newDiary.setMultiply(diary.getMultiply()>=0?1:-1);
								newDiary.setPrice(diary.getPrice());
								newDiary.setLotNo(s);
								newDiary.setValidityDate(diary.getValidityDate());
								newDiary.setBomStroe(diary.isBomStroe());
						    	lotNoStockCurrentDAO.stockAdd(newDiary);
						    }
						    diary.setLotNo(StringUtils.join(lotNos.iterator(), ","));
			       }
			     }
				return stockDiaryDAO.insert(diary);	
			}
    	}.exec();
    	
    	 
    }
    
    public int stockDiarySub(final String customer,final StockDiary diary)throws BasicException {
    	 return new SentenceExecTransaction(s) {
			@Override
			protected int execInTransaction(Object params) throws BasicException{
				StockDiary newDiary;
				if(!diary.isBomStroe()){
					List<BomIncludeProductInfo> bomProduct=listCascadeBomIncludeProductInfoById(diary.getProductID());
					for(BomIncludeProductInfo p:bomProduct){
						newDiary=new StockDiary();
						newDiary.setDate(diary.getDate());
						newDiary.setReason(diary.getReason());
						newDiary.setLocation(diary.getLocation());
						newDiary.setProductID(p.getIncludeProduct());
						//newDiary.setProductAttSetInstId(l.getProductAttSetInstId());
						newDiary.setMultiply(diary.getMultiply()*p.getUnits());
						newDiary.setPrice(diary.getPrice());
						newDiary.setLotNo(diary.getLotNo());
						newDiary.setValidityDate(diary.getValidityDate());
						newDiary.setBomStroe(p.isBomStore());
						newDiary.setBomId(diary.getProductID());
							
						if(newDiary.isBomStroe()){
							if(customer!=null)
								customerStorckCurrentDAO.stockSub(customer, diary);
							stockCurrentDAO.stockSub(diary);
						    if(diary.getLotNo()!=null)
						    	lotNoStockCurrentDAO.stockSub(diary);
						}
					   stockDiaryDAO.insert(newDiary);
					}
				}else{
					if(customer!=null)
						customerStorckCurrentDAO.stockSub(customer, diary);
				    stockCurrentDAO.stockSub(diary);
				    if(diary.getLotNo()!=null){
					    ArrayList<String> lotNos=com.openbravo.pos.util.StringUtils.splitProp(diary.getLotNo(),"\n");
					    for(String s:lotNos){
					    	newDiary=new StockDiary();
							newDiary.setDate(diary.getDate());
							newDiary.setReason(diary.getReason());
							newDiary.setLocation(diary.getLocation());
							newDiary.setProductID(diary.getProductID());
							if(lotNos.size()==1){
								newDiary.setMultiply(diary.getMultiply());
							}else
							    newDiary.setMultiply(diary.getMultiply()>=0?1:-1);
							newDiary.setPrice(diary.getPrice());
							newDiary.setLotNo(s);
							newDiary.setValidityDate(diary.getValidityDate());
							newDiary.setBomStroe(diary.isBomStroe());
					    	lotNoStockCurrentDAO.stockAdd(newDiary);
					     } 
		              }
					}
				return stockDiaryDAO.insert(diary);
			}
    	}.exec();
         
    }
    
    public List<ProductStoreView> getSimilarProductStoreQBF(Object filter) throws BasicException {
        return productStoreInfoDAO.getSimilarProductStoreQBF(filter);
    }

    public List<ProductStoreView> getProductBomIncludeStoreQBF(Object filter) throws BasicException {
        return productStoreInfoDAO.getProductBomIncludeStoreQBF(filter);
    }

    public List<ProductStoreView> getProductIncludeBomStoreQBF(Object filter) throws BasicException {
        return productStoreInfoDAO.getProductIncludeBomStoreQBF(filter);
    }

    public int paymentMovementInsert(final QuickPayment obj) throws BasicException{
    	return puickPaymentDAO.paymentMovementInsert(obj);
    }

    public int paymentMovementDelete(String receiptId,String paymentId)throws BasicException {
    	return puickPaymentDAO.paymentMovementDelete(receiptId, paymentId);
    }

    public final double findProductStock(String warehouse, String id, String attsetinstid) throws BasicException {
        Double d = stockCurrentDAO.findProductStock(warehouse, id, attsetinstid);
        return d == null ? 0.0 : d.doubleValue();
    }

    public int addCatalogProductCategory(String categoryId) throws BasicException {
        return productCategoryExtDAO.getCatalogProductCategoryAdd(categoryId);
    }

    public int delCatalogProductCategory(String categoryId) throws BasicException {
        return productCategoryExtDAO.delCatalogProductCategory(categoryId);
    }

    @Override
    public ProductPrefPrice getProductPrefPriceByProductID(String id) throws BasicException {
        return productPrefPriceDAO.getProductPrefPriceByProductID(id);
    }

    @Override
    public void saveTicket(final List<Ticket> tickets, final String location) throws BasicException {
        
    }

    //根据资源类型与对应值找服务定义
    @Override
    public Service findService(String serviceType, String srcId) throws BasicException {
        return serviceDAO.findService(serviceType, srcId);
    }

    //根据资源号找服务定义
    public Service findServiceById(String id) throws BasicException {
        return serviceDAO.findServiceById(id);
    }

    public final List listPeopleVisible() throws BasicException {
        return userInfoDAO.listPeopleVisible();
    }

    public final UserInfo findPeopleByCard(String card) throws BasicException {
        return userInfoDAO.findPeopleByCard(card);
    }

    public final UserInfo findPeopleByName(String name) throws BasicException {
        return userInfoDAO.findPeopleByName(name);
    }

    // Products list
    public final List listPlaceVisible() throws BasicException {
        return placeDAO.listPlaceVisible();
    }

    public final Place findPlaceByName(String name) throws BasicException {
        return placeDAO.findPlaceByName(name);
    }

    public UserInfo loadPeopleByID(String userId) throws BasicException {
        return userInfoDAO.loadPeopleByID(userId);
    }

    public ProductCustomerCategoryPrice findProductCustomerCategoryPrice(String productId, String customerCategoryId) throws BasicException {
        return productCustomerCategoryPriceDAO.findProductCustomerCategoryPrice(productId, customerCategoryId);
    }

    public List<Product> listProductByMnemonic(String filter) throws BasicException {
        return productDAO.listProductByMnemonic(filter);
    }

    public List<ServiceCalendarDayLine> listServiceCalendarDayLineByService(String serviceId) throws BasicException{
        return serviceCalendarDayLineDAO.listServiceCalendarDayLineByService(serviceId);
    }

    public List<ServiceCalendarWeakLine> listServiceCalendarWeakLineByService(String serviceId) throws BasicException{
        return serviceCalendarWeakLineDAO.listServiceCalendarWeakLineByService(serviceId);
    }

	@Override
	public Double findCustomerCategoryPrice(String productId,
			String customerCategoryId) throws BasicException {	
		
		return productCustomerCategoryPriceDAO.findCustomerCategoryPrice(productId, customerCategoryId);
	}

	@Override
	public PaymentsModel loadInstance(String cashIndex) throws BasicException {
		return closeCashDAO.loadInstance(cashIndex);
	}

	public Collection<I_CustomerDebtProcesser> getCustomerDebtProcessers() {
		return customerDebtProcessers;
	}

	public Product_V findProduct_VByProductId(String productId)throws BasicException{
		return product_VDAO.find(productId);
	}
	
	public byte[] findProductImage(String productId)throws BasicException{
		return productExtDAO.findProductImage(productId);
	}

	@Override
	public boolean isCustomer(String location) throws BasicException {
		return locationDAO.isCustomer(location);
	}

	@Override
	public List<ProductExt> getPrefPriceProductExt() throws BasicException {
		return productExtDAO.getPrefPriceProductExt();
	}

	@Override
	public List<ProductExt> getRecommendProducts(String productId)
			throws BasicException {
		ArrayList<ProductExt> ret=new ArrayList();
		if(productRecommends!=null)
			for(I_ProductRecommend recommend:productRecommends)
				ret.addAll(recommend.getRecommendProducts(productId));
		return ret;
	}

	@Override
	public List<Product> getBomIncludeProductListById(String productId)
			throws BasicException {
		return productDAO.getBomIncludeProductListById(productId);
	}

	@Override
	public List<Product> getProductBySimilarCodeNoSrc(String prodcutId,
			String smilarCode) throws BasicException {
		return productDAO.getProductBySimilarCodeNoSrc(prodcutId, smilarCode);
	}

	@Override
	public List<ProductStoreView> listByIdAndVirtual(String id,
			boolean isVirtual) throws BasicException {
		return productStoreInfoDAO.listByIdAndVirtual(id, isVirtual);
	}

    @Override
    public List<ProductStoreView> listProductStoreByProductID(String filter) throws BasicException {
        return productStoreInfoDAO.listProductStoreByProductID(filter);
    }

    @Override
	public CustomerStoreValueCard findStoreValueCardByNum(String value)
			throws BasicException {
		if(!customerDebtProcessers.isEmpty()) 
		   for(I_CustomerDebtProcesser processer:customerDebtProcessers)
     	       return processer.findStoreValueCardByNum(value);
		return customerStoreValueCardDAO.findStoreValueCardByNum(value);
	}
	
    public int customerStoreValueCardDiaryInsert(final StoreValueCardOPEnum opType,final CustomerStoreValueCardDiary diary)throws BasicException {
    	if(customerDebtProcessers.isEmpty()){
    	return new SentenceExecTransaction(s) {
			@Override
			protected int execInTransaction(Object params) throws BasicException{
				switch(opType){
				   case lost:
					   customerStoreValueCardDAO.changeCardState(diary.getCardId(), CustomerStoreValueCard.STATE_Loss);
					   break;
				   case recovery:
					   customerStoreValueCardDAO.changeCardState(diary.getCardId(), CustomerStoreValueCard.STATE_UseAble);
					   break;
				   case able:
					   customerStoreValueCardDAO.changeCardState(diary.getCardId(), CustomerStoreValueCard.STATE_UseAble);
					   break;
				   case back:
					   customerStoreValueCardDAO.changeCardState(diary.getCardId(), CustomerStoreValueCard.STATE_Back);
					   break;
				   case invalid:
					   customerStoreValueCardDAO.changeCardState(diary.getCardId(), CustomerStoreValueCard.STATE_Invalid);
					   break;
				   case transferIn:
					   customerStoreValueCardDAO.storeValueCard_In(diary.getCardId(), diary.getPrice());
					   break;
				   case transferOut:
					   customerStoreValueCardDAO.storeValueCard_Out(diary.getCardId(), -diary.getPrice());
					   break;
				   case consumer:
					   customerStoreValueCardDAO.consumerValueCard(diary.getCardId(), diary.getPrice());
					   break;
				   case recharge:
					   customerStoreValueCardDAO.rechargeValueCard(diary.getCardId(), diary.getPrice());
					   break;
				}
				return customerStoreValueCardDiaryDAO.insert(diary);
			}
    	}.exec();
    	}else for(I_CustomerDebtProcesser processer:customerDebtProcessers){
      	     processer.customerStoreValueCardDiaryInsert(opType, diary);
      	 }
        return 1;
    }
	
	public int transferStoreValueCardValue(final String descId,final CustomerStoreValueCardDiary diary)throws BasicException {
		if(customerDebtProcessers.isEmpty()){
		return new SentenceExecTransaction(s) {
			@Override
			protected int execInTransaction(Object params) throws BasicException{
				CustomerStoreValueCardDiary newDiary=new CustomerStoreValueCardDiary();
				newDiary.setCardId(descId);
				newDiary.setReason(diary.getCardId()+"->"+diary.getPrice());
				newDiary.setDate(diary.getDate());
				newDiary.setUserId(diary.getUserId());
				newDiary.setPrice(diary.getPrice());
				customerStoreValueCardDiaryInsert(StoreValueCardOPEnum.transferIn,newDiary);
				return customerStoreValueCardDiaryInsert(StoreValueCardOPEnum.transferOut,diary);
			}
    	}.exec();
		}else for(I_CustomerDebtProcesser processer:customerDebtProcessers){
   	     processer.transferStoreValueCardValue(descId, diary);
   	 }
     return 1;
	}

	@Override
	public BusinessPartner findCustomerByStoreCard(String cardNum)
			throws BasicException {
		return customerDAO.findCustomerByStoreCard(cardNum);
	}
	
	public int customerScoreDiaryInsert(final CustomerScoreOPEnum opType,final CustomerScoreDiary diary)throws BasicException{
		if(customerDebtProcessers.isEmpty()){
            // udate customer fields...
            //CustomerHelper.updateCurDebt(ticket.getCustomer(), -p.getTotal(), ticket.getDate());
            // insert customer fields...
			return new SentenceExecTransaction(s) {
				@Override
				protected int execInTransaction(Object params) throws BasicException{
					switch(opType){
					   case transferIn:
						   customerDAO.updateCurScore(diary.getCustomerId(), diary.getPrice());
						   break;
					   case transferOut:
						   customerDAO.updateCurScore(diary.getCustomerId(), -diary.getPrice());
						   break;
					   case consumer:
						   customerDAO.updateCurScore(diary.getCustomerId(), -diary.getPrice());
						   break;
					   case recharge:
						   customerDAO.updateCurScore(diary.getCustomerId(), diary.getPrice());
						   break;
					}
					return customerScoreDiaryDAO.insert(diary);
				}
	    	}.exec();
        	}else{
        		for(I_CustomerDebtProcesser processer:customerDebtProcessers){
            	     processer.customerScoreDiaryInsert(opType, diary);
            	 }
           }
		return 1;
	}

	@Override
	public List<Product> listProductByCustomer(String customerId)
			throws BasicException {
		return this.productDAO.listProductByCustomer(customerId);
	}

	@Override
	public List<ProductCustomerView> listProductCustomerViewByProductId(
			String productId) throws BasicException {
		return productCustomerViewDAO.listProductCustomerViewByProductId(productId);
	}


	@Override
	public void productUpdateIn(CustomerProduct product) throws BasicException {
		customerProductDAO.productUpdateIn(product);
	}


	@Override
	public void productUpdateOut(CustomerProduct product) throws BasicException {
		customerProductDAO.productUpdateOut(product);
	}


	@Override
	public ProductPrice findProductPriceByGroupAndProduct(String productId,
			String groupName) throws BasicException {
		return productPriceDAO.findProductPriceByGroupAndProduct(productId, groupName);
	}
	
	public void productBomBalance(final String locaId,final String productBomId)throws BasicException {
		final List<ProductBom> inBomProds=bomProductDAO.list(new I_ParentNode(){
			@Override
			public IKeyed getParentKey() {
				return KeyBuilder.getKey(productBomId);
			}

			@Override
			public Class getParentClass() {	
				return Product.class;
			}
		});
		if(inBomProds==null||inBomProds.isEmpty())
			return;
		final double unit=stockCurrentDAO.findProductStock(locaId, productBomId, null);
		if(unit==0.0)
			return;
		new SentenceExecTransaction(s) {
			@Override
			protected int execInTransaction(Object params) throws BasicException{
				StockDiary diary;
				for(ProductBom prodBom:inBomProds){
					diary=new StockDiary();
					diary.setDate(new Date());
					diary.setLocation(locaId);
					diary.setProductID(prodBom.getProductID());
					diary.setReason("Bom Balance");
					diary.setMultiply(unit*prodBom.getUnits());
					diary.setPrice(0);
					stockDiaryAdd(diary);
				}
				diary=new StockDiary();
				diary.setDate(new Date());
				diary.setLocation(locaId);
				diary.setProductID(productBomId);
				diary.setReason("Bom Balance");
				diary.setMultiply(unit);
				diary.setPrice(0);
				return stockDiarySub(diary);
			}
		}.exec();
		List<Product> inProds=this.productDAO.getBomIncludeProductListById(productBomId);
		for(Product p:inProds){
			if(!p.isBomStore())
				productBomBalance(locaId,p.getID());
		}
	}

	@Override
	public Voucher findVoucherByNum(String text) throws BasicException {
		return voucherDAO.findVoucherByNum(text);
	}

	@Override
	public ProductScore getProductScoreByProductAndType(String product, int type)
			throws BasicException {	
		return productScoreDAO.getProductScoreByProductAndType(product, type);
	}

	@Override
	public boolean isProductOutAble(String locationId, String product)
			throws BasicException {	
		return productLocationStateDAO.isProductOutAble(locationId, product);
	}

	@Override
	public boolean isProductLocked(String locationId, String product)
			throws BasicException {
		return productLocationStateDAO.isProductLocked(locationId, product);
	}

	@Override
	public boolean isProductInAble(String locationId, String product)
			throws BasicException {
		return productLocationStateDAO.isProductInAble(locationId, product);
	}

	@Override
	public void insertOrUpdateProductState(String locationId, String product,
			int state) throws BasicException {
		productLocationStateDAO.insertOrUpdateProductState(locationId, product, state);
	}

	@Override
	public boolean isProductStoreEnough(String inventoryLocation, String id,double quantity)
			throws BasicException {
		return stockCurrentDAO.findProductStock(inventoryLocation, id, null)>=quantity;
	}

	@Override
	public List<ProductExt> listNewProducts() throws BasicException {
		return productExtDAO.getNewProducts();
	}

	@Override
	public List<AttributeInstInfo> listAttributeInstInfo(String attsetId)
			throws BasicException {
		
		return attributeInstInfoDAO.listAttributeInstInfo(attsetId);
	}

	@Override
	public List<AttributeInstInfo> listAttributeInstInfo(String attsetId,
			String attsetinstid) throws BasicException {
		return attributeInstInfoDAO.listAttributeInstInfo(attsetId, attsetinstid);
	}

	@Override
	public String findAttributeSetInstanceId(String attsetid, String value)
			throws BasicException {
		return attributeSetInstanceDAO.findAttributeSetInstanceId(attsetid, value);
	}

	@Override
	public ProductAttributeValuePrice findProductAttributePrice(String attid, String value)
			throws BasicException {
		return productAttributeValuePriceDAO.findProductAttributePrice(attid, value);
	}

	@Override
	public List<AttributeValue> listAttributeValueByProduct(String productId)
			throws BasicException {	
		return this.attributeValueDAO.listAttributeValueByProduct(productId);
	}

	@Override
	public List<ProductExt> listPosShardProducts() throws BasicException {
		return productExtDAO.listPosShardProducts();
	}

	@Override
	public Product findProductByKeyStoke(String keyStoke) throws BasicException {
		return productDAO.findProductByKeyStoke(keyStoke);
	}


	@Override
	public List<BomIncludeProductInfo> listCascadeBomIncludeProductInfoById(
			String id) throws BasicException {
		ArrayList<BomIncludeProductInfo> retList=new ArrayList<BomIncludeProductInfo>();
		List<BomIncludeProductInfo> includeProductInfo=bomIncludeProductInfoDAO.list(id);
		for(BomIncludeProductInfo p:includeProductInfo){
			retList.add(p);
			if(!p.isBomStore()){
				List<BomIncludeProductInfo> subList=listCascadeBomIncludeProductInfoById(p.getIncludeProduct());
			    for(BomIncludeProductInfo s:subList){
			    	s.setUnits(p.getUnits()*s.getUnits());
			    	retList.add(s);
			    }
			}
		}
		return retList;
	}


	@Override
	public Class transParentClass(Class in) {
		return DateLogicUtils.transParentClass(in);
	}


	@Override
	public PhysicalBond findPhysicalBondByCard(String cardNum)
			throws BasicException {
		return physicalBondDAO.findPhysicalBondByCard(cardNum);
	}


	@Override
	public void physicalBondPayment(final String locaId,final PhysicalBond physicaBond)
			throws BasicException {
		new SentenceExecTransaction(s) {
			@Override
			protected int execInTransaction(Object params) throws BasicException{
				StockDiary diary=new StockDiary();
				diary.setDate(new Date());
				diary.setLocation(locaId);
				diary.setProductID(physicaBond.getProductId());
				diary.setReason("physicalBond");
				diary.setMultiply(1);
				diary.setPrice(0);
				stockDiarySub(diary);	
				return physicalBondDAO.updateByFields(physicaBond,new String[]{I_PhysicalBond.STATE,I_PhysicalBond.USEDATE},new Object[]{PhysicalBond.STATE_Used,new Date()});
			}
		}.exec();
		
	}

}
